#pragma once
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include "log.hpp"


#define SIZE 1024

// class UdpServer
// {
// public:
//     // 构造:将对应的端口号、IP传入
//     UdpServer(uint16_t port, std::string ip = "") // 对ip默认值说明：方便后续bind操作，1、可从任意IP获取数据(默认情况)，2、也可指定需要的IP（自己传入参数的情况）
//         : port_(port), ip_(ip), sock_(-1)
//     {
//     }

//     // 析构：关闭套接字
//     ~UdpServer()
//     {
//         if (sock_ >= 0)
//             close(sock_);
//     }

//     // 初始化服务器
//     bool InitServer()
//     {
//         // 1、创建套接字:此处AF_INET也可以是FP_INET
//         sock_ = socket(AF_INET, SOCK_DGRAM, 0);
//         if (sock_ < 0)
//         {
//             logMessage(ERROR, "%d:%s ", errno, strerror(errno));
//             exit(2);
//         }
//         logMessage(DEBUG, "创建套接字成功, sock: %d ", sock_);

//         // 2、bind绑定：
//         // 2.1、绑定前的准备工作：
//         struct sockaddr_in localaddr;
//         bzero(&localaddr, sizeof localaddr); // 将结构体清零
//         localaddr.sin_family = AF_INET; // 告知通讯方式，通常与domain同
//         localaddr.sin_port = htons(port_); // 端口号：注意转为网络字节序
//         localaddr.sin_addr.s_addr = ip_.empty() ? INADDR_ANY : inet_addr(ip_.c_str()); // IP：点分十进制->四字节+网络字节序
//         // 2.2、绑定：
//         if (bind(sock_, (struct sockaddr *)&localaddr, sizeof localaddr) < 0) // 注意对localaddr类型转换
//         {
//             logMessage(ERROR, "%d:%s", errno, strerror(errno));
//             exit(2);
//         }
//         logMessage(DEBUG, "绑定成功，初始化服务器完成！");

//         return true;
//     }

//     // 启动服务器
//     void Start()
//     {

//         // 1、作为一款网络服务器，永远不退出地在接收客服端通过网络传来的请求
//         while (true)
//         {
//             // 1.1、准备工作：
//             // a、用于后续从网络中读取客户端的IP、端口号
//             struct sockaddr_in clientaddr;
//             bzero(&clientaddr, sizeof clientaddr);
//             socklen_t len = sizeof clientaddr; // 输入输出型参数：输入时传递的是clientaddr当前定义的大小，使用是会输出实际大小
//             // b、用于存储数据
//             char server_buffer[SIZE];

//             // 1.2、读取数据：
//             ssize_t s = recvfrom(sock_, server_buffer, sizeof(server_buffer) - 1, 0, (struct sockaddr *)&clientaddr, &len); // 注意对clientaddr类型转换
//             if (s > 0) // 读取成功
//             {
//                 server_buffer[s] = 0;

//                 // a、获取客户端端口号、IP：因为是从网络中获取，这里本地显示时需要转换字节序和风格
//                 uint16_t client_port = ntohs(clientaddr.sin_port);
//                 std::string client_ip = inet_ntoa(clientaddr.sin_addr);
//                 printf("[%s:%d]# %s\n", client_ip.c_str(), client_port, server_buffer);

//                 // b、处理客服端发来的数据请求(自定义TODO)
//             }
//             // 2、响应：将处理好的结果返回。
//             sendto(sock_, server_buffer, strlen(server_buffer), 0, (struct sockaddr *)&clientaddr, len);
            
//         }
//     }

// private:
//     uint16_t port_;  // 端口号：16位的整数
//     std::string ip_; // IP地址：点分十进制字符串风格
//     int sock_;       // 通讯时的套接字：需要供多处使用
// };





class UdpServer
{
public:
    UdpServer(uint16_t port, const std::string &ip = "")
        : _port(port), _ip(ip), _sock(-1)
    {
    }
    ~UdpServer()
    {
        if (_sock >= 0)
            close(_sock);
    }

    bool ServerInit()
    {
        // 创建通信使用的套接字
        _sock = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sock < 0)
        {
            logMessage(ERROR, "%d:%s", errno, strerror(errno));
            exit(1);
        }
        logMessage(DEBUG, "创建套接字成功，sock:%d", _sock);

        // 绑定套接字+进程
        struct sockaddr_in serveraddr;
        bzero(&serveraddr, sizeof(serveraddr));
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_port = htons(_port);
        serveraddr.sin_addr.s_addr = _ip.empty()? INADDR_ANY : inet_addr(_ip.c_str());

        if (bind(_sock, (struct sockaddr *)&serveraddr, sizeof serveraddr) < 0)
        {
            logMessage(ERROR, "%d:%s", errno, strerror(errno));
        }
        logMessage(DEBUG, "绑定成功，初始化服务器完成。");
        return true;
    }

    void Start()
    {
        while (true)
        {
            struct sockaddr_in cilentaddr;
            bzero(&cilentaddr,sizeof(cilentaddr));
            socklen_t len = sizeof(cilentaddr);

            char server_buffer[SIZE];
            ssize_t ret = recvfrom(_sock,server_buffer,sizeof(server_buffer)-1,0,(struct sockaddr*)&cilentaddr,&len);
            if(ret > 0)
            {
                server_buffer[ret]=0;

                uint16_t client_port = ntohs(cilentaddr.sin_port);
                std::string client_ip = inet_ntoa(cilentaddr.sin_addr);
                printf("[%s:%d]# %s\n",client_ip.c_str(),client_port,server_buffer);

            }
            sendto(_sock,server_buffer,strlen(server_buffer),0,(struct sockaddr*)&cilentaddr,len);
        }
        
    }

private:
    int _sock;       // 套接字
    std::string _ip; // 点分十进制IP
    uint16_t _port;  // 端口号
};